/*
 * dttsp.c
 *
 *  Created on: 25-Apr-2009
 *      Author: bob
 */

#include "pydttsp.h"
#include <stdlib.h>
#include <stdio.h>
#include <stdbool.h>

/*
 * Necessary to compile successfully in python 2.3
 * Thanks to Mark Rages for the patch
 */
#ifndef Py_RETURN_NONE
#define Py_RETURN_NONE return Py_INCREF(Py_None), Py_None
#endif

//-------------------------------------------------------------------------------
DTTSP_STATIC PyObject *py_setup(
				PyObject *self,
				PyObject *args) {
	setup();
	Py_RETURN_NONE;
}

//-------------------------------------------------------------------------------
DTTSP_STATIC PyObject *py_closeup(
				PyObject *self,
				PyObject *args) {
	closeup();
	Py_RETURN_NONE;
}

//-------------------------------------------------------------------------------
DTTSP_STATIC PyObject *py_do_samples(
				PyObject *self,
				PyObject *args) {

	// Params
	int frames;
	PyObject* left_obj;
	PyObject* right_obj;

	// Workspace
	PyObject* left_obj_seq;
	PyObject* right_obj_seq;
	char type_error_msg[30] = "Not a sequence";
	int i;

	// Python output side
	PyObject *I;
	PyObject *Q;
	PyObject *IQ;

	// Parse out the parameters
	if (!PyArg_ParseTuple(args,
							"OOi",
							&left_obj,
							&right_obj,
							&frames)) {
		Py_RETURN_NONE;
	}

	I = PyTuple_New(frames);
	Q = PyTuple_New(frames);
	IQ = PyTuple_New(2);

	// Clear the buffers
	memset((char*)buf_l, 0, (size_t)MAX_FLOAT_FRAMES*sizeof(float));
	memset((char*)buf_r, 0, (size_t)MAX_FLOAT_FRAMES*sizeof(float));

	// Copy the sequence data into the transfer buffers
	left_obj_seq = PySequence_Fast(left_obj, type_error_msg);
	right_obj_seq = PySequence_Fast(right_obj, type_error_msg);
	PyObject* p;
	for (i=0; i<frames; i++) {
		p = PySequence_Fast_GET_ITEM(left_obj_seq, i);
		buf_l[i] = (float)PyFloat_AsDouble(p);
		p = PySequence_Fast_GET_ITEM(right_obj_seq, i);
		buf_r[i] = (float)PyFloat_AsDouble(p);
	}

	// Call the DSP engine
	do_samples(buf_l, buf_r, frames);
	// After the call the result is in the in/out buffers
	// Copy output to Python sequence
	for (i=0; i<frames; i++) {
		PyTuple_SET_ITEM(I, i, PyFloat_FromDouble((double)buf_l[i]));
		PyTuple_SET_ITEM(Q, i, PyFloat_FromDouble((double)buf_r[i]));
	}
	PyTuple_SET_ITEM(IQ, 0, I);
	PyTuple_SET_ITEM(IQ, 1, Q);

	// Release memory
	Py_DECREF(left_obj_seq);
	Py_DECREF(right_obj_seq);

	return IQ;
}

//-------------------------------------------------------------------------------
DTTSP_STATIC PyObject *py_do_update(
				PyObject *self,
				PyObject *args) {

	// Params
	char* command;

	// Workspace

	// Parse out the parameters
	if (!PyArg_ParseTuple(args,
							"s",
							&command)) {
		Py_RETURN_NONE;
	}

	do_update(command);

	Py_RETURN_NONE;
}

//-------------------------------------------------------------------------------
DTTSP_STATIC PyObject *py_resample(
				PyObject *self,
				PyObject *args) {
	Py_RETURN_NONE;
}

//-------------------------------------------------------------------------------
DTTSP_STATIC PyObject *py_do_panadapter(
				PyObject *self,
				PyObject *args) {
	// Params
	int radio;

	// Workspace
	float* spec_in;
	int i;
	int sz;

	// Python output side
	PyObject *spec_out;

	// Parse out the parameters
	if (!PyArg_ParseTuple(args,
							"i",
							&radio)) {
		Py_RETURN_NONE;
	}

	// Create the buffer to receive the spec data
	sz = spec_size();
	spec_in = (float*)malloc(sz*sizeof(float));

	// Create the python object to receive the output data
	spec_out = PyTuple_New(sz);

	// Get the spectrum data
	process_panadapter(radio, spec_in);
	// After the call the result is in spec_in

	// Copy output to Python sequence
	for (i=0; i<sz; i++) {
		PyTuple_SET_ITEM(spec_out, i, PyFloat_FromDouble((double)spec_in[i]));
	}

	return spec_out;
}

//-------------------------------------------------------------------------------
DTTSP_STATIC PyObject *py_do_rx_meter(
				PyObject *self,
				PyObject *args) {
	// Params
	int radio;

	// Workspace
	float* meter_in;
	int i;
	int sz;

	// Python output side
	PyObject *meter_out;

	// Parse out the parameters
	if (!PyArg_ParseTuple(args,
							"i",
							&radio)) {
		Py_RETURN_NONE;
	}

	// Create the buffer to receive the meter data
	sz = meter_size();
	meter_in = (float*)malloc(sz*sizeof(float));

	// Create the python object to receive the output data
	meter_out = PyTuple_New(sz);

	// Get the meter data
	process_rx_meter(radio, meter_in);
	// After the call the result is in meter_in

	// Copy output to Python sequence
	for (i=0; i<sz; i++) {
		PyTuple_SET_ITEM(meter_out, i, PyFloat_FromDouble((double)meter_in[i]));
	}

	return meter_out;
}

//-------------------------------------------------------------------------------
// Method declarations
DTTSP_STATIC PyMethodDef dttsp_Methods[] = {

		{"pySetup",
			py_setup,
			METH_VARARGS},

		{"pyCloseup",
			py_closeup,
			METH_VARARGS},

		{"pyDoSamples",
			py_do_samples,
			METH_VARARGS},

		{"pyDoUpdate",
			py_do_update,
			METH_VARARGS},

		{"pyResample",
			py_resample,
			METH_VARARGS},

		{"pyDoPanadapter",
			py_do_panadapter,
			METH_VARARGS},

		{"pyDoRxMeter",
			py_do_rx_meter,
			METH_VARARGS},

		{NULL, NULL}
};

#ifndef PyMODINIT_FUNC
#define PyMODINIT_FUNC void
#endif /* PyMODINIT_FUNC */

/*
 * Entry point for the module
 */
PyMODINIT_FUNC initlibdttsp(void)
{
	PyObject *module;

	module = Py_InitModule3("libdttsp", dttsp_Methods,"DttSp access module");
	if (!module) return;

	// Create buffers large enough for the maximum frame size
	buf_l = (float*) PyMem_Malloc((size_t)MAX_FLOAT_FRAMES*sizeof(float));
	buf_r = (float*) PyMem_Malloc((size_t)MAX_FLOAT_FRAMES*sizeof(float));
}
